package cn.wh.interceptor;

import cn.wh.annotation.DataScope;
import cn.wh.entity.User;
import cn.wh.entity.req.DataScopeParam;
import cn.wh.util.BaseUtil;
import cn.wh.util.RedisUtil;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.handler.DataPermissionHandler;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.HexValue;
import net.sf.jsqlparser.expression.LongValue;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
import net.sf.jsqlparser.expression.operators.relational.InExpression;
import net.sf.jsqlparser.expression.operators.relational.ItemsList;
import net.sf.jsqlparser.schema.Column;
import org.apache.catalina.security.SecurityUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @Author wanghao
 * @Date 2022/5/1 14:52
 * @Description: TODO
 */
@Aspect
@Slf4j
@Component
public class DataScopePermissionHandler extends BaseUtil implements DataPermissionHandler {

    @Resource
    private RedisUtil redisUtil;
    @Resource
    private HttpServletRequest request;
    /**
     * 通过ThreadLocal记录权限相关的属性值
     */
    ThreadLocal<DataScopeParam> threadLocal = new ThreadLocal<>();


    @After("dataScopePointCut()")
    public void cleanCach() {
        threadLocal.remove();
        log.info("清除上一次缓存信息");
    }

    @Pointcut("@annotation(cn.wh.annotation.DataScope)")
    public void dataScopePointCut() {

    }

    @Before("dataScopePointCut()")
    public void doBefore(JoinPoint joinPoint) {
        //获得注解
        DataScope annotationLog = getAnnotationLog(joinPoint);
        if (annotationLog != null) {
            String token = request.getHeader("token");
       //     User user = (User) redisUtil.get(token);
            User user = new User(1L,"","","张三",false, Set.of(1,2));
            DataScopeParam dataScopeParam = new DataScopeParam
                    (annotationLog.deptAlias(), annotationLog.deptField(), user.getIsAdmin(), user.getSecretary());
            threadLocal.set(dataScopeParam);
            log.info("获得注解并注入属性{}", dataScopeParam);
        }
    }

    /**
     * 是否存在注解,如果存在就获取
     *
     * @param joinPoint
     * @return
     */
    private DataScope getAnnotationLog(JoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        if (method != null) {
            return method.getAnnotation(DataScope.class);
        }
        return null;
    }

    /**
     * @param where
     * @param mappedStatementId
     * @return
     */
    @Override
    public Expression getSqlSegment(Expression where, String mappedStatementId) {
        log.debug("DataPermissionHandler 运行了");
        DataScopeParam dataScopeParam = threadLocal.get();
        if (dataScopeParam == null || dataScopeParam.isAdmin()) {
            return where;
        }
        if (where == null) {
            where = new HexValue("1=1");
        }
        String deptSql = "".equals(dataScopeParam.getDeptAlias()) ? dataScopeParam.getDeptField() : dataScopeParam.getDeptAlias() + "." + dataScopeParam.getDeptField();
        // 把集合转变为JSQLParser需要的元素列表
        ItemsList itemsList;
        if (CollectionUtils.isEmpty(dataScopeParam.getSecretary())) {
            //如果权限为空，则只能看自己部门的
            itemsList = new ExpressionList(Collections.singletonList(new LongValue(getUser().getId())));
        } else {
            //查看权限内的数据
            itemsList = new ExpressionList(dataScopeParam.getSecretary().stream().map(LongValue::new).collect(Collectors.toList()));
        }
        InExpression inExpression = new InExpression(new Column(deptSql), itemsList);
        log.debug("where = {}", where);
        log.debug("inExpression = {}", inExpression);
        return new AndExpression(where, inExpression);
    }
}
